/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phonebooksharing.android.activities.media;

import java.io.IOException;
import java.text.DecimalFormat;

import com.phonebooksharing.android.R;
import com.phonebooksharing.android.activities.media.Slider.OnPositionChangedListener;
import com.phonebooksharing.android.util.CloseableUtil;

import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class AudioHandler implements OnBufferingUpdateListener, OnCompletionListener, MediaPlayer.OnPreparedListener {

    /** TAG for log messages. */
    private static final String TAG = "PlayerActivity";
    protected boolean isPlaying;
    protected MediaPlayer mp;
    protected TextView mPositionText, mBuffer;
    protected Button mPlay, mStop, mReset;
    protected Slider mSlider;
    protected Context cx;
    
    public AudioHandler(Context c, View audioView) {
        this.cx = c;
        
        mBuffer = (TextView)audioView.findViewById(R.id.buffer);
        mBuffer.setText("0%");
        mBuffer.setTextColor(0xff000088);
        
        mPositionText = (TextView)audioView.findViewById(R.id.position);
        mPositionText.setText("00:00 / 00:00");
        mPositionText.setTextColor(0xff000088);
        
        mSlider = (Slider)audioView.findViewById(R.id.slider);
        mSlider.setPosition(0);
        mSlider.setOnPositionChangedListener(new OnPositionChangedListener() {
            /**
             * Changed slider to new position.
             * 
             * @see org.openintents.widget.Slider.OnPositionChangedListener#onPositionChangeCompleted()
             */
            public void onPositionChangeCompleted(Slider slider) {
                int newPos = slider.pos;
                if (mp != null) {
                    mp.seekTo(newPos);
                }
            }

            public void onPositionChanged(Slider slider, int oldPosition, int newPosition) {
                // Update text field:
                if (mp != null) {
                    int timeMax = mp.getDuration();
                    mPositionText.setText("" + formatTime(newPosition) + " / " + formatTime(timeMax));
                }
            }
        });
        
        mPlay = (Button)audioView.findViewById(R.id.play);
        mPlay.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                if(isPlaying) {
                    pauseMedia();
                } else {
                    playMedia();
                }
            }
        });
        
        mStop = (Button)audioView.findViewById(R.id.stop);
        mStop.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                stopMedia();
            }
        });
        
        mReset = (Button)audioView.findViewById(R.id.reset);
        mReset.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                resetMedia();
            }
        });
    }

    private static final int UPDATE_POSITION = 1;
    /** Handler for timing messages. */
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == UPDATE_POSITION) {
                if (mp == null || !isPlaying) {
                    mPositionText.setText("00:00 / 00:00");
                    mSlider.min = 0;
                    mSlider.max = 100;
                    mSlider.setPosition(0);
                    isPlaying = false;
                } else {
                    int time = mp.getCurrentPosition();
                    int timeMax = mp.getDuration();
                    if (mSlider.mTouchState == Slider.STATE_RELEASED) {
                        mPositionText.setText("" + formatTime(time) + " / " + formatTime(timeMax));
                    }

                    mSlider.min = 0;
                    mSlider.max = timeMax;
                    mSlider.setPosition(time);

                    if (isPlaying) {
                        sendMessageDelayed(obtainMessage(UPDATE_POSITION), 200);
                    }
                }
            }
        }
    };
    
    public String localFile; Uri uri;
    
    public void setMedia(Uri uri) {
        this.uri = uri;
    }
    
    public void playMedia(Uri uri) {
        this.uri = uri;
        this.localFile = null;
        playMedia();
    }
    
    public void playMedia(String localFile) {
        this.localFile = localFile;
        this.uri = null;
        playMedia();
    }
    
    public void pauseMedia() {
        mPlay.setBackgroundResource(R.drawable.mp_play_1);
        if (isPlaying) {
            mp.pause();
        }
        isPlaying = false;
    }
    
    public void stopMedia() {
        if (isPlaying) {
            CloseableUtil.safeClose(mp);
            mp = null;
        }
        mPlay.setBackgroundResource(R.drawable.mp_play_1);
        isPlaying = false;
    }

    public void resetMedia() {
        if (mp != null) {
            mp.seekTo(0);
        }
    }
    
    protected void playMedia() {
        try {
            Log.i(TAG, "Starting music");
            // If the path has not changed, just start the media player
            mPlay.setBackgroundResource(R.drawable.mp_pause_1);
            if (mp != null) {
                Log.i(TAG, "Re-start music");

                mSlider.setEnabled(true);
                mp.start();
                if (!isPlaying) {
                    isPlaying = true;
                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_POSITION));
                }
                return;
            }

            // Create a new media player and set the listeners
            mp = new MediaPlayer();
            // mp.setOnErrorListener(this);
            mp.setOnBufferingUpdateListener(this);
            mp.setOnCompletionListener(this);
            mp.setOnPreparedListener(this);
            mp.setAudioStreamType(2);

            try {
                if(uri != null) {
                    mp.setDataSource(cx, uri);
                } else {
                    mp.setDataSource(localFile);
                }
            } catch (IOException e) {
                Log.e(TAG, e.getMessage(), e);
            }
            try {
                mp.prepareAsync();
            } catch (Exception e) {
                e.printStackTrace();
            }
            isPlaying = true;
        } catch (Exception e) {
            Log.e(TAG, "error: " + e.getMessage(), e);
        }
    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
        Log.d(TAG, "onBufferingUpdate percent:" + percent);

        if (percent < 100) {
            mBuffer.setText("Buffering " + percent + " %");
        } else {
            mBuffer.setText("Buffer completed!");
        }
    }

    /**
     * Is called when the song reached is final position.
     */
    public void onCompletion(MediaPlayer arg0) {
        Log.d(TAG, "onCompletion called");
        // Let us clean up
        if (mp != null) {
            mp.release();
            mp = null;
        }
        mSlider.setEnabled(false);
        isPlaying = false;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        Log.d(TAG, "onPrepared called");
        mp.start();
        mHandler.sendMessage(mHandler.obtainMessage(UPDATE_POSITION));
    }

    static DecimalFormat mTimeDecimalFormat = new DecimalFormat("00");

    public static String formatTime(int ms) {
        int s = ms / 1000; // seconds
        int m = s / 60;
        s = s - 60 * m;
        int h = m / 60;
        m = m - 60 * h;
        String m_s = mTimeDecimalFormat.format(m) + ":" + mTimeDecimalFormat.format(s);
        if (h > 0) {
            // show also hour
            return "" + h + ":" + m_s;
        } else {
            // Show only minute:second
            return m_s;
        }
    }

    public void clean() {
        CloseableUtil.safeClose(mp);
        mp = null;

        mPositionText = null; mBuffer = null;
        mPlay = null; mStop = null; mReset = null;
        mSlider = null; cx = null; mHandler = null;
    }
}
